package com.shr.xsunmvc;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.logging.Logger;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.shr.xsunmvc.route.Route;
import com.shr.xsunmvc.route.RouteMatch;
import com.shr.xsunmvc.route.Routers;
import com.shr.xsunmvc.servlet.packer.Request;
import com.shr.xsunmvc.servlet.packer.Response;
import com.shr.xsunmvc.util.PathUtils;
import com.shr.xsunmvc.util.ReflectUtil;

/**
 * xsunmvc 核心Filter
 * @author sun haoran
 *
 */
public class XsunFilter implements Filter {

	private static final Logger LOGGER = Logger.getLogger(XsunFilter.class.getName());
	private RouteMatch routeMatch = new RouteMatch(new ArrayList<>());
	private ServletContext servletContext;

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		Xsun xsun = Xsun.me();
		if (!xsun.isInit()) {

			String className = filterConfig.getInitParameter("initialization");
			try {
				Class<?> clazz = Class.forName(className);
				Initialization initial = (Initialization) clazz.newInstance();
				initial.init(xsun);

				Routers routers = xsun.getRouters();
				if (routers != null) {
					routeMatch.setRoute(routers.getRoutes());
				}
				servletContext = filterConfig.getServletContext();

				xsun.setInit(true);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;

		String uri = PathUtils.getRelativePath(request);

		LOGGER.info("Request URI:" + uri);

		Route route = routeMatch.findRoute(uri);

		if (route != null) {
			handle(request, response, route);
		}else{
			chain.doFilter(request, response);
		}
	}

	private void handle(HttpServletRequest servletRequest, HttpServletResponse servletResponse, Route route) {
		Request request = new Request(servletRequest);
		Response response = new Response(servletResponse);

		XsunContext.initContext(servletContext, request, response);
		Object controller = route.getController();

		Method method = route.getMethod();
		executeMethod(controller, method, request, response);
	}

	/**
	 * 执行路由对应的方法
	 * @param controller 控制器对象
	 * @param method 控制器方法
	 * @param request 
	 * @param response
	 * @return
	 */
	private Object executeMethod(Object controller, Method method, Request request, Response response) {
		int len = method.getParameterTypes().length;
		method.setAccessible(true);
		if (len > 0) {
			Object[] args = getArgs(request, response, method.getParameterTypes());
			return ReflectUtil.invokeMethod(controller, method, args);
		} else
			return ReflectUtil.invokeMethod(controller, method);
	}

	/**
	 * 根据参数类型获取参数对象，处理response和request参数顺序不一样的情况
	 * @param request
	 * @param response
	 * @param parameterTypes
	 * @return
	 */
	private Object[] getArgs(Request request, Response response, Class<?>[] parameterTypes) {
		int len = parameterTypes.length ;
		Object[] args = new Object[len] ;
		for(int i = 0;i<len;i++){
			if(parameterTypes[i].getName().equals(Request.class.getName())){
				args[i] = request ;
			}
			if(parameterTypes[i].getName().equals(Response.class.getName())){
				args[i] = response ;
			}
		}
		return args;
	}

	@Override
	public void destroy() {
		
	}

}
